const { loadEnv } = require('vite')
const axios = require('axios');
const fs = require('fs');
const FormData = require('form-data');
const importChalk = () => import('chalk').then(({default: chalk}) => chalk);
const COS = require('cos-nodejs-sdk-v5');
const OSS = require("ali-oss");
const log = console.log;
const envs = loadEnv(process.env.NODE_ENV, process.cwd())
const { VITE_SITE_URL } = envs

const UPLOAD_FILE_PATH = 'upload/shotstack/apk'

async function getWorkAiConfig() {
  const { data } = await axios.get(`${VITE_SITE_URL}/public/system/config`).then(res => res.data)
  let org_id = data.basic.oem_org_id || 1

  const { data: config } = await axios.get(`${VITE_SITE_URL}/work_ai/config?org_id=${org_id}`).then(res => res.data)
  return config.list
}

async function getUploadDriver() {
  let aiConfig = await getWorkAiConfig()

  if (aiConfig.shotstack_driver == "alionline"){
    aiConfig.upload_driver = 'oss'
  }

  return aiConfig.upload_driver
}

function getCosConfig(scopes) {
  return axios.post(`${VITE_SITE_URL}/work_ai/upload/cos/config`, {
    ...(scopes ? { scopes } : {})
  }).then(res => res.data)
}

function getOssConfig() {
  return axios.post(`${VITE_SITE_URL}/work_ai/upload/oss/config/ststoken`, {
    is_pack: 1,
  }).then(res => res.data)
}

function createLocalInstance(){
  const upload = async function(filePath){
    const chalk = await importChalk()

    log(chalk.blue.bgGreen.bold('开始上传...'), filePath)

    const form = new FormData();
    form.append('file', fs.createReadStream(filePath), filePath.split('/').pop());

    const response = await axios.post(`${VITE_SITE_URL}/work_ai/shotstack/electron-upload`, form, {
      headers: {
        ...form.getHeaders()
      },
      onUploadProgress: (progressEvent) => {
        const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
        console.log(chalk.blue.bgGreen.bold('上传进度'), `${percentCompleted}%`);
      },
      maxContentLength: Infinity,
      maxBodyLength: Infinity,
    }).then(res => res.data)

    if(response.code != 1000){
      throw new Error(response.msg)
    }

    return {
      fileName: response.data.path,
      fileUrl: response.data.url
    }
  }

  return {
    upload: upload,
    multipartUpload: upload
  }
}

function createCosInstance() {
  const cos = new COS({
    getAuthorization: async function (options, callback) {
      const { data: uploadConfig } = await getCosConfig(options.Scope)

      const credentials = uploadConfig.credentials;

      if(! credentials){
          throw new Error('获取临时凭证失败')
      }

      callback({
          TmpSecretId: credentials.tmpSecretId,
          TmpSecretKey: credentials.tmpSecretKey,
          SecurityToken: credentials.sessionToken,
          StartTime: uploadConfig.startTime,
          ExpiredTime: uploadConfig.expiredTime,
          ScopeLimit: true,
      });
    }
  });

  const upload = async function(filePath, uploadPath, headers = {}){
    const chalk = await importChalk()

    log(chalk.blue.bgGreen.bold('开始上传...'), filePath)

    const { data: uploadConfig } = await axios.post(`${VITE_SITE_URL}/work_ai/upload/cos/config`).then(res => res.data)

    if (! uploadPath){
      const fileName = filePath.split('/').pop();
      uploadPath = `${UPLOAD_FILE_PATH}/${fileName}`
    }

    const responseData = await (() => {
      return new Promise((resolve, reject) => {
        cos.uploadFile({
          Bucket: uploadConfig.cos.bucket,
          Region: uploadConfig.cos.region,
          Key: uploadPath,
          FilePath: filePath,
          SliceSize: 1024 * 1024 * 5,
          AsyncLimit: 3,
          onProgress: (progressData) => {
            log(chalk.blue.bgGreen.bold('上传进度'), (progressData.percent * 100).toFixed(2) + '%')
          },
          Headers: {
            ...headers
          }
        }, (err, data) => {
          if (err) {
            reject(err)
          } else {
            resolve({
              fileName: uploadPath,
              fileUrl: uploadConfig.cos.domain + '/' + uploadPath
            })
          }
        })
      })
    })()

    return responseData
  }

  return {
    client: cos,
    upload: upload,
    multipartUpload: upload,
    head: async function(filePath){
      cos.headObject({
        Bucket: uploadConfig.cos.bucket,
        Region: uploadConfig.cos.region,
        Key: filePath,
      }, function(err, data) {
          console.log(err || data, 'zzzzzzzzzz');
      });
    }
  }
}

async function createOssInstance() {
  const response = await getOssConfig()

  const oss_config = response.data.sts;

  const client = new OSS({
    bucket: oss_config.bucket,
    region: oss_config.region,
    endpoint: oss_config.endpoint,
    accessKeyId: oss_config.AccessKeyId,
    accessKeySecret: oss_config.AccessKeySecret,
    secure: false,
    connectTimeout: 300000,
    timeout: 60000 * 60,
    stsToken: oss_config.stsToken,
  });

  return {
    client,
    upload: async function(filePath, uploadPath, headers = {}){
      const chalk = await importChalk();

      if (! uploadPath){
        const fileName = filePath.split('/').pop();
        uploadPath = `${UPLOAD_FILE_PATH}/${fileName}`
      }

      const responseData = await (() => {
        return new Promise(async (resolve, reject) => {
          try {
            const responseData = await client.put(
              uploadPath,
              filePath,
              {
                headers: {
                  ...headers,
                },
              }
            );

            resolve({
              fileName: responseData.name,
              fileUrl: `${oss_config.domain}/${responseData.name}`,
            })
          } catch (error) {
            log(chalk.blue.bgGreen.bold("阿里云上传的错误"), error);
            reject(error);
          }
        })
      })()

      return responseData
    },
    multipartUpload: async function(filePath, uploadPath, headers = {}){
      const chalk = await importChalk();

      if (! uploadPath){
        const fileName = filePath.split('/').pop();
        uploadPath = `${UPLOAD_FILE_PATH}/${fileName}`
      }

      const responseData = await (() => {
        return new Promise(async (resolve, reject) => {
          try {
            const responseData = await client.multipartUpload(
              uploadPath,
              filePath,
              {
                // partSize: config.partSize || 1024 * 1024 * 5,
                // parallel: config.parallel || 2,
                progress: (p) => {
                  log(
                    chalk.blue.bgGreen.bold(`上传进度:`),
                    (p * 100).toFixed(2) + "%"
                  );
                },
                headers: {
                  ...headers,
                },
              }
            );

            resolve({
              fileName: responseData.name,
              fileUrl: `${oss_config.domain}/${responseData.name}`,
            })
            console.log('上传成功：',`${oss_config.domain}/${responseData.name}`); 
            console.log('当前域名：',VITE_SITE_URL);
          } catch (error) {
            log(chalk.blue.bgGreen.bold("阿里云上传的错误"), error);
            reject(error);
          }
        })
      })()

      return responseData
    },
    head: async function(filePath){
      return client.head(filePath)
    }
  }
}

function createUploader(driver) {
  if(driver === 'cos'){
    return createCosInstance()
  }

  if(driver === 'oss'){
    return createOssInstance()
  }

  return createLocalInstance()
}


module.exports = {
  upload: async function(filePath, uploadPath){
    const uploadDriver = await getUploadDriver()

    const uploader = await createUploader(uploadDriver)

    filePath = filePath.replaceAll('\\', '/')

    return uploader.upload(filePath,  uploadPath)
  },
  multipartUpload: async function(filePath, uploadPath){
    const uploadDriver = await getUploadDriver()

    const uploader = await createUploader(uploadDriver)

    filePath = filePath.replaceAll('\\', '/')

    return uploader.multipartUpload(filePath,  uploadPath)
  },
  getUploadDriver: getUploadDriver,
  createUploader: createUploader,
  getOssConfig: getOssConfig,
  getCosConfig: getCosConfig
}
